class BlackDeathWeapon extends Weapon
	abstract
	notplaceable;
		
var(Animations) name	WeaponEquipAnim;
var(Sounds) SoundCue 	WeaponEquipSnd;
var name FireAnim, AltFireAnim;

var int WeaponDamage;
var int HeavyWeaponDamage;

var float MaxEquipLength; //The longest possible equip time (note, not a safe operation yet, could call equip functions twice)
var float MaxUnequipLength;  //The longest possible Unequip time (note, not a safe operation yet, could call Unequip functions twice)
var float MaxRefireLength; //The longest possible Refire time (note, not a safe operation yet, could call Unequip functions twice)

/** Holds the amount of Stamina used for a given shot */
var array<int> StaminaCost;
var bool isHidden;
var bool old_animations;

var float recoil;

var bool bWeaponEquipAnims; //true if weapon has equip animations, if false then the weapon will skip equip and unequip anims. (useful for wepons like zombie claws that never change and should be ready right away).

var EWeapAnimType WeapAnimType;

/**Weapon types:
0 - None
1 - fists
2 - sword
3 - Torch
Expand as neccisary
*/
var int WeaponType;

simulated function PostBeginPlay()
{
	super.PostBeginPlay();
	isHidden = false;
}

simulated function AttachWeaponTo(SkeletalMeshComponent MeshCpnt, optional Name SocketName ) //default function that equips the wepon to some socket on some mesh
{
	local BlackDeathPawn BDP;
	BDP = BlackDeathPawn(Instigator);
	if (BDP.Mesh != None)
		if ( Mesh != None )
		{
			Mesh.SetShadowParent(BDP.Mesh);
			Mesh.SetLightEnvironment(BDP.LightEnvironment);
			BDP.Mesh.AttachComponentToSocket(Mesh, SocketName);
			`log("Weapon "@self@" Socketed to: "@SocketName);
		}

}

/** updates to these function are neccisary since unsocketed wepon unequiping is not handeled yet. */
simulated function DetachWeapon()//Note: consider deleteing DetachFrom and moving all detach functionality to here.
{
	DetachFrom(Instigator.Mesh);
}

simulated function DetachFrom( SkeletalMeshComponent MeshCpnt )
{
/*
	if ( Mesh != None )
	{
		Mesh.SetShadowParent(None);
		Mesh.SetLightEnvironment(None);
		SetSkin(None);
	}
	if ( MeshCpnt != None )
	{
		// detach weapon mesh from player skelmesh
		if ( Mesh != None )
		{
			MeshCpnt.DetachComponent( mesh );
		}

		//BDPawn = BlackDeathPawn(Instigator);

		SetBase(None);
		SetHidden(True);
	}*/
}

simulated function ChangeVisibility(bool bIsVisible)//hides wepon mesh, used by the invmanager to hide weapons when the pawn hides
{
	//`log("Changing visibility of"@self);
	if (Mesh != None)
	{
		Mesh.SetHidden(!bIsVisible);
		isHidden = !bIsVisible;
	}
}
//Rewrites equiping to work based on anim calls rather then a timer as in the parent class
simulated state WeaponEquipping 
{
	simulated event BeginState(Name PreviousStateName)
	{
		`LogInv("");
		bWeaponPutDown	= false;
		if(bWeaponEquipAnims)
		{
			TimeWeaponEquipping();
			SetTimer(MaxEquipLength, false, 'FailSafeEquip');//calls equip functions if for some reason the animation doesn't (usually if the animation does no the the proper function calls)
		}
		else
		{
			FailSafeEquip();
		}
	}
	
	simulated function WeaponEquipped()
	{
		if( bWeaponPutDown )
		{
			// if switched to another weapon, put down right away
			PutDownWeapon();
			return;
		}

		GotoState('Active');
		ClearTimer('FailSafeEquip');
	}
}

simulated function WeaponEquipped()
{
}

simulated function TimeWeaponEquipping()
{
	PlayWeaponEquip();
}

function FailSafeEquip()
{
	local BlackDeathPawn BDP;
	BDP = BLackDeathPawn(instigator);
	if(BDP != none)
	{
		BDP.AnimAttachWeaponToHand();
	}
	WeaponEquipped();
}

function FinishEquip()
{
	WeaponEquipped();
}

simulated state WeaponPuttingDown //same as above but with unequiping
{
	simulated event BeginState(Name PreviousStateName)
	{
		`LogInv("");

		bWeaponPutDown = FALSE;
		if(bWeaponEquipAnims)
		{
			TimeWeaponPutDown();
			SetTimer(MaxUnequipLength, false, 'FailSafeUnequip');//calls unequip functions if for some reason the animation doesn't (usually if the animation does no the the proper function calls)
		}
		else
		{
			FailSafeUnequip();
		}
		// Make sure all pending fires are cleared.
		ForceEndFire();
	}
	simulated function WeaponIsDown()
	{
		if( InvManager.CancelWeaponChange() )
		{
			return;
		}

		`LogInv("");

		// This weapon is down, remove it from the mesh
		DetachWeapon();

		// Put weapon to sleep
		//@warning: must be before ChangedWeapon() because that can reactivate this weapon in some cases
		GotoState('Inactive');

		// switch to pending weapon
		InvManager.ChangedWeapon();
		ClearTimer('FailSafeUnequip');
	}
}

simulated function TimeWeaponPutDown()
{
	PlayWeaponPutDown();
}

function FailSafeUnequip()
{
	local BlackDeathPawn BDP;
	BDP = BLackDeathPawn(instigator);
	if(BDP != none)
	{
		BDP.AnimRemoveWeaponFromHand();
	}
	WeaponIsDown();
}

function FinishUnequip()
{
	WeaponIsDown();
}

simulated state active //notifier here to tell the pawn to switch into his atracking idle now that the wepon is active
{
	simulated event BeginState(Name PreviousStateName)
	{
		NotifyPawnWeaponActive();
		Super.BeginState(PreviousStateName);
	}
}

simulated function NotifyPawnWeaponActive() //handels telling BDPawn that the wepaon is active
{
	local BlackDeathPawn BDP;
	BDP = BlackDeathPawn(instigator);
	if(BDP != none)
	{
		switch( WeaponType ){
			case 3: // idle torch
				BDP.NotifyPawnTorchActive();
				break;
			default: // idle 2 handed
				BDP.NotifyPawnWeaponActive();
		}
	}
}

simulated state WeaponFiring //Updates wepon logic to use anim notifiers rather then a timer when fireing.
{
	simulated function RefireCheckTimer()
	{
		//WorldInfo.Game.Broadcast(none, "refire check timer"); 
		// if switching to another weapon, abort firing and put down right away
		if( bWeaponPutDown )
		{
			`LogInv("Weapon put down requested during fire, put it down now");
			PutDownWeapon();
			return;
		}

		
		if( ShouldRefire() )
		{
			WorldInfo.Game.Broadcast(none, "calling refire"); 

			FireAmmunition();
			SetTimer(MaxRefireLength, false, 'RefireCheckTimer');
			return;
		}

		// Otherwise we're done firing
		HandleFinishedFiring();
	}

	simulated event BeginState( Name PreviousStateName )
	{
		`LogInv("PreviousStateName:" @ PreviousStateName);
		`log(self@": Begining fireingstate");
		// Fire the first shot right away
		FireAmmunition();
		SetTimer(MaxRefireLength, false, 'RefireCheckTimer'); //calls refire check manually if for some reason the animation doesn't (usually if the animation does no the the proper function calls)
	}
}

/** Notifiers added to tell the pawn that the wepon fired (usually only the PlayerController is told that the wepon fired) */
function NotifyWeaponFired( byte FireMode )
{
	local BlackDeathPawn BDP;
	BDP = BlackDeathPawn(Instigator);
	if(BDP != none)
	{
		BDP.NotifyAttacking();
	}
	Super.NotifyWeaponFired( FireMode );
}

function NotifyWeaponFinishedFiring( byte FireMode )
{
	local BlackDeathPawn BDP;
	BDP = BlackDeathPawn(Instigator);
	ForceEndFire(); //No queueing up fire commands, this ensures there can't be another shot unless the player pulls the trigger. -Reza
	if(BDP != none)
	{
		BDP.NotifyEndAttaking();
	}
	Super.NotifyWeaponFinishedFiring( FireMode );
}

simulated function EndSwing() //override base function with new function call (may be able to delte this, not sure where all functions calls are in base class.
{
	RefireCheckTimer();
}

simulated function PlayWeaponEquip()
{
	local BlackDeathPawn BDP;
	BDP = BlackDeathPawn(Instigator);
	if(BDP != none)
	{
		if( old_animations ){
			BDP.PlayAnim( equip_sword );
		}
		else {
			switch( WeaponType ){
				case 2: //sword
					BDP.PlayAnim( equip_sword );
				break;
				case 3: //torch
					BDP.PlayAnim( equip_torch );
				break;
			}
		}
	}
}

simulated function PlayWeaponPutDown()
{
	local BlackDeathPawn BDP;
	BDP = BlackDeathPawn(Instigator);
	if(BDP != none)
	{
		if( old_animations ){
			BDP.PlayAnim( unequip_torch );
		}
		else {
			switch( WeaponType ){
				case 3: //puts down torch
					BDP.PlayAnim( unequip_torch );
					//BDP.NotifyPawnWeaponActive();
				break;
				default: //puts down sword
					BDP.PlayAnim( unequip_sword );
					//BDP.NotifyPawnTorchActive();
				break;
			}
		}
	}
}

function CallAttack()
{
}

simulated function WeaponPlaySound(SoundCue Sound, optional float NoiseLoudness)
{
	// if we are a listen server, just play the sound.  It will play locally
	// and be replicated to all other clients.
	if( Sound != None && Instigator != None )
	{
		Instigator.PlaySound(Sound, false, true);
	}
}
simulated function SetSkin(Material NewMaterial)
{
	local int i,Cnt;

	if ( NewMaterial == None )	// Clear the materials
	{
		if ( default.Mesh.Materials.Length > 0 )
		{
			Cnt = Default.Mesh.Materials.Length;
			for (i=0;i<Cnt;i++)
			{
				Mesh.SetMaterial( i, Default.Mesh.GetMaterial(i) );
			}
		}
		else if (Mesh.Materials.Length > 0)
		{
			Cnt = Mesh.Materials.Length;
			for ( i=0; i < Cnt; i++ )
			{
				Mesh.SetMaterial(i,none);
			}
		}
	}
	else
	{
		if ( default.Mesh.Materials.Length > 0 || mesh.GetNumElements() > 0 )
		{
			Cnt = default.Mesh.Materials.Length > 0 ? default.Mesh.Materials.Length : mesh.GetNumElements();
			for ( i=0; i < Cnt; i++ )
			{
				Mesh.SetMaterial(i,NewMaterial);
			}
		}
	}
}

simulated function FireAmmunition()
{
	`log(self@": fireing ammo");
	CosumeStamina( CurrentFireMode );
	Super.FireAmmunition();
}

function CosumeStamina( byte FireModeNum )
{
	// consumes stamina from the hero pawn when a weapon is swung
	local BlackDeathHeroPawn BDHP;
	BDHP = BlackDeathHeroPawn(Instigator);
	if(BDHP != none)
	{
		BDHP.WeaponConsumeStamina(StaminaCost[FireModeNum]);
	}
}

simulated function AttachToHolder(SkeletalMeshComponent MeshCpnt, Name SocketName ) //change in function name for conveniance, this should be cleaned up later.
{
	//`log("Attaching to holder Socket "@SocketName);
	AttachWeaponTo(MeshCpnt, SocketName);
}

function bool DenyPickupQuery(class<Inventory> ItemClass, Actor Pickup)
{
	return false;
}
	
DefaultProperties
{
	bHidden = false;
	WeaponEquipAnim=WeaponEquip
	
	MaxEquipLength=10.0
	MaxUnequipLength=10.0
	MaxRefireLength=10.0
	
	bWeaponEquipAnims=true;
	
	recoil = 0.5

	WeaponType = 0
	
	StaminaCost(0)=5
	StaminaCost(1)=10
	EquipTime = 0.01
	
	//switch for usig old animations true old animation set false recently updated animations
	old_animations = false;
}